%include "pm.inc"

%ifdef DOS_DEBUG
org 0100h
%else
org 07c00h
%endif

PageDirBase0 equ 200000h
PageTblBase0 equ 201000h
PageDirBase1 equ 210000h
PageTblBase1 equ 211000h

LinearAddrDemo equ 00401000h
ProcFoo equ 00401000h
ProcBar equ 00501000h
ProcPagingDemo equ 00301000h

jmp LABEL_BEGIN

[SECTION .gdt]
LABEL_GDT: Descriptor 0, 0, 0
LABEL_DESC_CODE32: dq 0x409a007c600157
LABEL_DESC_STACK: dq  0x4093007c40001f
LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR | DA_32 | DA_LIMIT_4K
LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW | DA_LIMIT_4K
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW

GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1
    dd 0
	
	
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
SelectorFlatC equ LABEL_DESC_FLAT_C - LABEL_GDT
SelectorFlatRW equ LABEL_DESC_FLAT_RW - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT

[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
	times 32 db 0
	
TopOfStack equ $ - LABEL_STACK - 1


[SECTION .s32]
[BITS 32]
LABEL_SEG_CODE32:	
	mov ax, SelectorVideo
	mov gs, ax
	mov ax, SelectorStack
	mov ss, ax
	
	mov esp, TopOfStack
	
	call PagingDemo
	
	jmp $

SetupPaging:
	mov ax, SelectorFlatRW
	mov es, ax
	mov edi, [esp + 4]
	; 此处写死为8，如果物理内存不是16M，则需要修改此处。实际就是PageTableNumber
	mov ecx, 8
	xor eax, eax
	mov eax, [esp + 8]
	add eax, PG_P | PG_USU | PG_RWW
.1:
	stosd ; 相当于 mov DWORD [es:edi], eax; add edi, 4
	add eax, 4096
	loop .1
	
	; 此处写死为8，如果物理内存不是16M，则需要修改此处。
	mov eax, 8
	mov ebx, 1024
	mul ebx
	mov ecx, eax
	mov edi, [esp + 8]
	xor	eax, eax
	mov eax, PG_P | PG_USU | PG_RWW
.2:
	stosd
	add eax, 4096
	loop .2
	
	ret

SetupPagingDirReg:
	mov eax, [esp + 4]
	mov cr3, eax
	ret
	
OpenPageMode:
	mov eax, cr0
	or eax, 80000000h
	mov cr0, eax
	nop 
	nop
	ret

PagingDemo:
	mov ax, cs
	mov ds, ax
	mov ax, SelectorFlatRW
	mov es, ax
	
	mov	edi, ProcFoo	; Destination
	mov	esi, OffsetFoo	; Source
	mov	ecx, LenFoo	; Counter
	rep movsb
	
	mov	edi, ProcBar	; Destination
	mov	esi, OffsetBar	; Source
	mov	ecx, LenBar	; Counter
	rep movsb
	
	mov	edi, ProcPagingDemo	; Destination
	mov	esi, OffsetPagingDemoProc	; Source
	mov	ecx, LenPagingDemoAll	; Counter
	rep movsb
		
	push PageTblBase0
	push PageDirBase0
	call SetupPaging
	add esp, 8
	
	push PageDirBase0
	call SetupPagingDirReg
	add esp, 4
	
	call OpenPageMode
	
	call SelectorFlatC:ProcPagingDemo
	call PSwitch
	call SelectorFlatC:ProcPagingDemo

PSwitch:
	push PageTblBase1
	push PageDirBase1
	call SetupPaging
	add esp, 8
	
	mov eax, LinearAddrDemo
	shr eax, 22
	mov ebx, 4096
	mul ebx
	mov ecx, eax
	mov eax, LinearAddrDemo
	shr eax, 12
	and eax, 03FFh
	mov ebx, 4
	mul ebx
	add eax, ecx
	add eax, PageTblBase1
	mov dword [es:eax], ProcBar | PG_P | PG_USU | PG_RWW
	
	push PageDirBase1
	call SetupPagingDirReg
	add esp, 4
	ret
	
PagingDemoProc:
OffsetPagingDemoProc equ PagingDemoProc - $$
	mov eax, LinearAddrDemo
	call eax
	retf
LenPagingDemoAll equ  $ - PagingDemoProc

foo:
OffsetFoo equ foo - $$
	mov ah, 0Ch
	mov al, 'F'
	mov [gs:((80 * 17 + 0) * 2)], ax
	ret
LenFoo equ $ - foo

bar:
OffsetBar equ bar - $$
	mov	ah, 0Ch			; 0000: 黑底    1100: 红字
	mov	al, 'B'
	mov	[gs:((80 * 18 + 0) * 2)], ax	; 屏幕第 18 行, 第 0 列。
	ret
LenBar			equ	$ - bar

SegCode32Len equ $ - LABEL_SEG_CODE32

[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, 0100h	

	xor eax, eax
	mov ax, ds
	shl eax, 4
	add eax, LABEL_GDT
	mov dword [GdtPtr + 2], eax

	lgdt [GdtPtr]

	cli

	in al, 92h
	or al, 00000010b
	out 92h, al

	mov eax, cr0
	or eax, 1
	mov cr0, eax

	jmp dword SelectorCode32:0